<i18n locale="zh-CN" lang="yaml">
API Example: API 调用示例

Request Options: 请求选项
Async          : 异步执行
Save Result    : 保留结果
Func Timeout   : 函数超时
API Timeout    : API 超时

Calling Parameters: 调用参数
Calling Example   : 调用示例
Simple GET        : GET 简化形式
Normal GET        : GET 标准形式
Simple POST (JSON): POST 简化形式（JSON）
Simple POST (Form): POST 简化形式（表单）
Normal POST       : POST 标准形式

'The JSON inside "kwargs" is the call parameter, modify its value and check out the calling example below': '"kwargs" 内的 JSON 即为调用参数，修改其中的值并在下方查看具体调用示例'
'This Python function allows additional parameters (**kwargs syntax)'                                     : '本 Python 函数支持传递额外的参数（**kwargs 语法）'
'This Python function allows uploading files, field name of the uploading file is "files"'                : '本 Python 函数支持文件上传，文件字段名为"files"'

This API does not require any parameter                  : 此 API 不需要任何参数
Invalid Parameters. Examples require a valid Body content: 参数填写存在错误，正确填写后将展示示例

'Only string arguments are allowed in this from'                                                                                                                       : '此方式参数值只支持字符串'
'Parameter "kwargs" should be URL encoded in HTTP request'                                                                                                             : '发送请求时，"kwargs" 参数需要进行 URL encode 编码'
'Parameter "options" are not supported in this from'                                                                                                                   : '此方式不支持 "options" 参数'
'When posting form data, "Content-Type" should be "multipart/form-data" or "application/x-www-form-urlencoded", and the values of the fields support string value only': 'POST 表单数据时，"Content-Type" 必须指定为 "multipart/form-data" 或 "application/x-www-form-urlencoded"，此时 Body 中参数值只支持字符串'
'When posting JSON data, "Content-Type" should be "application/json"'                                                                                                  : 'POST JSON 数据时，"Content-Type" 必须指定为 "application/json"'
'When uploading files, "Content-Type" should be "multipart/form-data"'                                                                                                 : '上传文件时，"Content-Type" 必须指定为 "multipart/form-data"'
'File uploading is not supported in this this form'                                                                                                                    : '此方式不支持文件上传'
</i18n>

<!-- Generated by OpenCC START -->
<i18n locale="zh-HK" lang="yaml">
API Example: API 調用示例
API Timeout: API 超時
Async: 異步執行
Calling Example: 調用示例
Calling Parameters: 調用參數
File uploading is not supported in this this form: 此方式不支持文件上傳
Func Timeout: 函數超時
Invalid Parameters. Examples require a valid Body content: 參數填寫存在錯誤，正確填寫後將展示示例
Normal GET: GET 標準形式
Normal POST: POST 標準形式
Only string arguments are allowed in this from: 此方式參數值只支持字符串
Parameter "kwargs" should be URL encoded in HTTP request: 發送請求時，"kwargs" 參數需要進行 URL encode 編碼
Parameter "options" are not supported in this from: 此方式不支持 "options" 參數
Request Options: 請求選項
Save Result: 保留結果
Simple GET: GET 簡化形式
Simple POST (Form): POST 簡化形式（表單）
Simple POST (JSON): POST 簡化形式（JSON）
The JSON inside "kwargs" is the call parameter, modify its value and check out the calling example below: '"kwargs" 內的 JSON 即為調用參數，修改其中的值並在下方查看具體調用示例'
This API does not require any parameter: 此 API 不需要任何參數
This Python function allows additional parameters (**kwargs syntax): 本 Python 函數支持傳遞額外的參數（**kwargs 語法）
This Python function allows uploading files, field name of the uploading file is "files": 本 Python 函數支持文件上傳，文件字段名為"files"
When posting JSON data, "Content-Type" should be "application/json": POST JSON 數據時，"Content-Type" 必須指定為 "application/json"
? When posting form data, "Content-Type" should be "multipart/form-data" or "application/x-www-form-urlencoded", and the values of the fields support string value only
: POST 表單數據時，"Content-Type" 必須指定為 "multipart/form-data" 或 "application/x-www-form-urlencoded"，此時 Body 中參數值只支持字符串
When uploading files, "Content-Type" should be "multipart/form-data": 上傳文件時，"Content-Type" 必須指定為 "multipart/form-data"
</i18n>
<i18n locale="zh-TW" lang="yaml">
API Example: API 呼叫示例
API Timeout: API 超時
Async: 非同步執行
Calling Example: 呼叫示例
Calling Parameters: 呼叫引數
File uploading is not supported in this this form: 此方式不支援檔案上傳
Func Timeout: 函式超時
Invalid Parameters. Examples require a valid Body content: 引數填寫存在錯誤，正確填寫後將展示示例
Normal GET: GET 標準形式
Normal POST: POST 標準形式
Only string arguments are allowed in this from: 此方式引數值只支援字串
Parameter "kwargs" should be URL encoded in HTTP request: 傳送請求時，"kwargs" 引數需要進行 URL encode 編碼
Parameter "options" are not supported in this from: 此方式不支援 "options" 引數
Request Options: 請求選項
Save Result: 保留結果
Simple GET: GET 簡化形式
Simple POST (Form): POST 簡化形式（表單）
Simple POST (JSON): POST 簡化形式（JSON）
The JSON inside "kwargs" is the call parameter, modify its value and check out the calling example below: '"kwargs" 內的 JSON 即為呼叫引數，修改其中的值並在下方檢視具體呼叫示例'
This API does not require any parameter: 此 API 不需要任何引數
This Python function allows additional parameters (**kwargs syntax): 本 Python 函式支援傳遞額外的引數（**kwargs 語法）
This Python function allows uploading files, field name of the uploading file is "files": 本 Python 函式支援檔案上傳，檔案欄位名為"files"
When posting JSON data, "Content-Type" should be "application/json": POST JSON 資料時，"Content-Type" 必須指定為 "application/json"
? When posting form data, "Content-Type" should be "multipart/form-data" or "application/x-www-form-urlencoded", and the values of the fields support string value only
: POST 表單資料時，"Content-Type" 必須指定為 "multipart/form-data" 或 "application/x-www-form-urlencoded"，此時 Body 中引數值只支援字串
When uploading files, "Content-Type" should be "multipart/form-data": 上傳檔案時，"Content-Type" 必須指定為 "multipart/form-data"
</i18n>
<!-- Generated by OpenCC END -->

<template>
  <el-dialog
    :title="title || $t('API Example')"
    :visible.sync="show"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    width="950px">
    <span>
      <el-divider content-position="left"><h1>{{ $t('Calling Parameters') }}</h1></el-divider>
      <el-row :gutter="20" v-if="apiBodyInput || supportCustomKwargs">
        <el-col :span="22">
          <el-input
            type="textarea"
            autosize
            resize="none"
            v-model="apiBodyInput">
          </el-input>
          <InfoBlock type="info" v-if="apiBodyInput.indexOf('kwargs') >= 0"
            :title="$t('The JSON inside &quot;kwargs&quot; is the call parameter, modify its value and check out the calling example below')" />
          <InfoBlock type="success" v-if="supportCustomKwargs"
            :title="$t('This Python function allows additional parameters (**kwargs syntax)')" />
          <InfoBlock type="success" v-if="supportFileUpload"
            :title="$t('This Python function allows uploading files, field name of the uploading file is &quot;files&quot;')" />
        </el-col>
        <el-col :span="2">
          <CopyButton :content="apiBodyInput" />
        </el-col>
      </el-row>
      <span class="text-info" v-else>
        {{ $t('This API does not require any parameter') }}
      </span>

      <template v-if="showOptions">
        <el-divider content-position="left"><h1>{{ $t('Request Options') }}</h1></el-divider>
        <el-form class="call-options" label-width="120px">
          <el-form-item :label="$t('Return Type')" v-if="showReturnTypeOption">
            <el-radio-group
              v-model="callOptions.returnType"
              :disabled="callOptionsUseDefault.returnType"
              size="mini">
              <el-radio-button label="raw">{{ $t('Raw') }}</el-radio-button>
              <el-radio-button label="jsonDumps">{{ $t('JSON-dump String') }}</el-radio-button>
            </el-radio-group>
            <el-checkbox class="use-default" v-model="callOptionsUseDefault.returnType">{{ $t('Use Default') }}</el-checkbox>
          </el-form-item>

          <el-form-item :label="$t('Unbox Result')" v-if="showUnboxOption">
            <el-switch
              v-model="callOptions.unbox"
              :disabled="callOptionsUseDefault.unbox"
              :inactive-value="false"
              :active-value="true">
            </el-switch>
            <el-checkbox class="use-default" v-model="callOptionsUseDefault.unbox">{{ $t('Use Default') }}</el-checkbox>
          </el-form-item>

          <el-form-item :label="$t('Delay')" v-if="showDelayOption">
            <el-input-number
              v-model="callOptions.delay"
              :disabled="callOptionsUseDefault.delay"
              size="mini"
              step-strictly
              :step="1"
              :precision="0"
              :min="0">
            </el-input-number>&emsp;{{ $tc('nSeconds', callOptions.delay, { n: '' }) }}
            <el-checkbox class="use-default" v-model="callOptionsUseDefault.delay">{{ $t('Use Default') }}</el-checkbox>
          </el-form-item>
        </el-form>
      </template>

      <el-divider content-position="left"><h1>{{ $t('Calling Example') }}</h1></el-divider>
      <template v-if="!apiBody">
        <span class="text-bad">{{ $t('Invalid Parameters. Examples require a valid Body content') }}</span>
      </template>
      <template v-else>
        <!-- Example -->
        <template v-if="showGetExample || showPostExample">
          <el-tabs tab-position="top">
            <el-tab-pane :label="$t('Simple GET')" v-if="showGetExample && showGetExampleSimple">
              <el-row :gutter="20">
                <el-col :span="22">
                  <el-link v-if="onlyStringParameter"
                    :href="getExample('simplified')"
                    :underline="true"
                    type="primary"
                    target="_blank"
                    class="get-example">
                    <code v-html="getExample('simplified', { asHTML: true, decodeURL: true })"></code>
                  </el-link>
                  <InfoBlock
                    :type="onlyStringParameter ? 'info' : 'error'"
                    :title="$t('Only string arguments are allowed in this from')" />
                  <InfoBlock v-if="showOptions" :title="$t('Parameter &quot;options&quot; are not supported in this from')" />
                </el-col>
                <el-col :span="2">
                  <CopyButton v-if="onlyStringParameter" :content="getExample('simplified')" />
                </el-col>
              </el-row>
            </el-tab-pane>

            <el-tab-pane :label="$t('Normal GET')" v-if="showGetExample && showGetExampleNormal">
              <el-row :gutter="20">
                <el-col :span="22">
                  <el-link
                    :href="getExample('normal')"
                    :underline="true"
                    type="primary"
                    target="_blank"
                    class="get-example">
                    <code v-html="getExample('normal', { asHTML: true, decodeURL: true })"></code>
                  </el-link>
                  <br>
                  <InfoBlock type="info" :title="$t('Parameter &quot;kwargs&quot; should be URL encoded in HTTP request')" />
                </el-col>
                <el-col :span="2">
                  <CopyButton :content="getExample('normal')" />
                </el-col>
              </el-row>
            </el-tab-pane>

            <el-tab-pane :label="$t('Simple POST (JSON)')" v-if="showPostExample && showPostExampleSimple && showPostExampleSimpleJSON">
              <el-row :gutter="20">
                <el-col :span="22">
                  <el-input
                    :value="postExample('simplified', { contentType: 'json' })"
                    :autosize="{ minRows: 6 }"
                    type="textarea"
                    resize="none"
                    readonly></el-input>
                  <InfoBlock type="info" :title="$t('When posting JSON data, &quot;Content-Type&quot; should be &quot;application/json&quot;')" />
                  <InfoBlock v-if="showOptions" :title="$t('Parameter &quot;options&quot; are not supported in this from')" />
                </el-col>
                <el-col :span="2">
                  <CopyButton :content="postExample('simplified', { contentType: 'json', oneLine: true })" />
                </el-col>
              </el-row>
            </el-tab-pane>

            <el-tab-pane :label="$t('Simple POST (Form)')" v-if="showPostExample && showPostExampleSimple && showPostExampleSimpleForm">
              <el-row :gutter="20">
                <el-col :span="22">
                  <el-input
                    :value="postExample('simplified', { contentType: 'form' })"
                    :autosize="{ minRows: 6 }"
                    type="textarea"
                    resize="none"
                    readonly></el-input>
                  <InfoBlock type="info" :title="$t('When posting form data, &quot;Content-Type&quot; should be &quot;multipart/form-data&quot; or &quot;application/x-www-form-urlencoded&quot;, and the values of the fields support string value only')" />
                  <InfoBlock v-if="supportFileUpload" type="warning" :title="$t('When uploading files, &quot;Content-Type&quot; should be &quot;multipart/form-data&quot;')" />
                  <InfoBlock v-if="showOptions" type="error" :title="$t('Parameter &quot;options&quot; are not supported in this from')" />
                </el-col>
                <el-col :span="2">
                  <CopyButton v-if="onlyStringParameter" :content="postExample('simplified', { contentType: 'form', oneLine: true })" />
                </el-col>
              </el-row>
            </el-tab-pane>

            <el-tab-pane :label="$t('Normal POST')" v-if="showPostExample && showPostExampleNormal">
              <el-row :gutter="20">
                <el-col :span="22">
                  <el-input
                    :value="postExample('normal')"
                    :autosize="{ minRows: 6 }"
                    type="textarea"
                    resize="none"
                    readonly></el-input>
                  <InfoBlock type="info" :title="$t('When posting JSON data, &quot;Content-Type&quot; should be &quot;application/json&quot;')" />
                  <InfoBlock v-if="supportFileUpload" type="error" :title="$t('File uploading is not supported in this this form')" />
                </el-col>
                <el-col :span="2">
                  <CopyButton :content="postExample('normal', { oneLine: true })" />
                </el-col>
              </el-row>
            </el-tab-pane>
          </el-tabs>
        </template>
      </template>
    </span>
  </el-dialog>
</template>

<script>
export default {
  name: 'APIExampleDialog',
  components: {
  },
  watch: {
  },
  methods: {
    prettyURLForHTML(url) {
      if (!url) return '';

      try {
        let urlParts = url.split('?');
        if (!urlParts[1]) return url;

        let paramParts = urlParts[1].split('&');
        for (let i = 0; i < paramParts.length; i++) {
          if (i === 0) {
            paramParts[i] = '?' + paramParts[i];
          } else {
            paramParts[i] = '&' + paramParts[i];
          }
        }

        let prettied = urlParts[0] + '<br>' + paramParts.join('<br>');

        return prettied;

      } catch(err) {
        console.error(err);
        return url;
      }
    },
    makeAPIBody(apiBody) {
      apiBody = this.T.jsonCopy(apiBody);

      if (this.T.isNothing(apiBody)) return apiBody;

      // No kwargs
      if (this.T.isNothing(apiBody.kwargs) && !this.supportCustomKwargs) {
        delete apiBody.kwargs;
      }

      // No options
      if (this.T.isNothing(apiBody.options)) {
        delete apiBody.options;
      }

      // Skip **kwargs、files
      if (this.T.notNothing(apiBody.kwargs)) {
        for (let k in apiBody.kwargs) {
          if (k.indexOf('**') === 0 || k === 'files') delete apiBody.kwargs[k];
        }
      }

      return apiBody;
    },

    update(apiURL, apiBody, funcKwargs) {
      apiBody         = apiBody         || {};
      apiBody.kwargs  = apiBody.kwargs  || {};
      apiBody.options = apiBody.options || {};

      this.apiKwargs  = this.T.jsonCopy(apiBody.kwargs);
      this.funcKwargs = this.T.jsonCopy(funcKwargs) || {};

      // Prepare API body
      apiBody = this.makeAPIBody(apiBody);

      let apiBodyInput = ''
      if (this.T.notNothing(apiBody)) {
        apiBodyInput = JSON.stringify(apiBody, null, 2);
      }

      this.apiURL       = apiURL;
      this.apiBodyInput = apiBodyInput;

      this.show = true;
    },

    getExample(format, opt) {
      if (!this.apiBody) return null;

      format = format || 'normal';

      opt = opt || {};
      opt.asHTML    = opt.asHTML    || false;
      opt.decodeURL = opt.decodeURL || false;

      let body = this.makeAPIBody(this.apiBody) || {};

      let url   = null;
      let query = {};
      switch(format) {
        // Normal format
        case 'normal':
          query = body || query;
          url = this.T.formatURL(this.apiURL, { query: query });
          break;

        // Simplified format
        case 'simplified':
          query = body.kwargs || query;
          url = this.T.formatURL(this.apiURL_simplified, { query: query });
          break;
      }

      if (opt.asHTML)    url = this.prettyURLForHTML(url);
      if (opt.decodeURL) url = decodeURIComponent(url);

      return url;
    },
    postExample(format, opt) {
      if (!this.apiBody) return null;

      format = format || 'normal';

      opt = opt || {};
      opt.oneLine     = opt.oneLine     || false;
      opt.contentType = opt.contentType || 'json';

      let body = this.makeAPIBody(this.apiBody) || {};

      let url = null;
      let shellNewLine = `\\\n`;
      let cURLOpts = [`curl`, shellNewLine, `-X`, `POST`, shellNewLine ];

      switch(format) {
        // Normal format
        case 'normal':
          if (this.T.notNothing(body)) {
            cURLOpts.push(`-H`, `"Content-Type: application/json"`, shellNewLine);
            cURLOpts.push(`-d`, `'${JSON.stringify(body)}'`, shellNewLine);
          }
          cURLOpts.push(this.apiURL);
          break;

        // Simplified format
        case 'simplified':
          // API body
          if (this.T.notNothing(body.kwargs)) {
            switch(opt.contentType) {
              case 'json':
                cURLOpts.push(`-H`, `"Content-Type: application/json"`, shellNewLine);
                cURLOpts.push(`-d`, `'${JSON.stringify(body.kwargs)}'`, shellNewLine);
                break;

              case 'form':
                if (this.supportFileUpload) {
                  cURLOpts.push(`-H`, `"Content-Type: multipart/form-data"`, shellNewLine);
                  for (let k in body.kwargs) {
                    cURLOpts.push(`-F`, `'${k}=${body.kwargs[k]}'`, shellNewLine);
                  }

                } else {
                  cURLOpts.push(`-H`, `"Content-Type: application/x-www-form-urlencoded"`, shellNewLine);
                  cURLOpts.push(`-d`, `'${this.T.formatQuery(body.kwargs)}'`, shellNewLine);
                }
                break;
            }
          }

          // Upload file
          if (this.supportFileUpload) {
            cURLOpts.push(`-F`, `files=@UPLOAD_FILE_PATH`, shellNewLine);
          }

          cURLOpts.push(this.apiURL_simplified);
          break;
      }

      if (opt.oneLine) {
        cURLOpts = cURLOpts.filter(item => item !== shellNewLine);
      }

      let cURLCmd = cURLOpts.join(' ');
      return cURLCmd;
    },
  },
  computed: {
    showOptions() {
      return this.showReturnTypeOption
            || this.showUnboxOption
            || this.showDelayOption;
    },

    apiURL_simplified() {
      return `${this.apiURL}/s`;
    },
    apiBody() {
      if (!this.apiBodyInput) return {};

      let obj = null;
      try {
        obj = JSON.parse(this.apiBodyInput);
      } catch(err) {
        // Unable to parse JSON
        return null;
      }

      if (this.showOptions) {
        let nextOptions = {};
        for (let k in this.callOptions) {
          if (this.T.notNothing(this.callOptions[k])) {
            nextOptions[k] = this.callOptions[k];
          }
        }

        if (this.T.notNothing(nextOptions)) {
          obj.options = nextOptions;
        }
      }

      return obj;
    },
    onlyStringParameter() {
      if (!this.apiBody) return false;

      let kwargs = this.apiBody.kwargs || {};
      for (let k in kwargs) {
        if ('string' !== typeof kwargs[k]) return false;
      }

      return true;
    },
    supportFileUpload() {
      if (this.apiKwargs && this.apiKwargs.files) {
        return this.common.isFuncArgumentPlaceholder(this.apiKwargs.files);
      }
      return false;
    },
    supportCustomKwargs() {
      if (this.funcKwargs) {
        for (let k in this.funcKwargs) {
          if (k.indexOf('**') === 0) return true;
        }
      }
      return false;
    },
  },
  props: {
    title: String,

    showReturnTypeOption: {
      type: Boolean,
      default: false,
    },
    showUnboxOption: {
      type: Boolean,
      default: false,
    },
    showDelayOption: {
      type: Boolean,
      default: false,
    },

    showGetExample: {
      type: Boolean,
      default: true,
    },
    showPostExample: {
      type: Boolean,
      default: true,
    },

    showGetExampleSimple: {
      type: Boolean,
      default: true,
    },
    showGetExampleNormal: {
      type: Boolean,
      default: true,
    },
    showPostExampleSimple: {
      type: Boolean,
      default: true,
    },
    showPostExampleSimpleJSON: {
      type: Boolean,
      default: true,
    },
    showPostExampleSimpleForm: {
      type: Boolean,
      default: true,
    },
    showPostExampleNormal: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      show: false,

      apiURL      : null,
      apiBodyInput: null,
      apiKwargs   : null,
      funcKwargs  : null,

      callOptionsUseDefault: {
        returnType: true,
        unbox     : true,
        delay     : true,
      },

      callOptions: {
        returnType: null,
        unbox     : null,
        delay     : null,
      },
    }
  },
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.get-example {
  margin-bottom: 20px;
}
.get-example .el-link--inner {
  padding: 0 5px;
}
.call-options .el-form-item {
  margin-top: 0;
  margin-bottom: 0;
}
.call-options .use-default {
  float: right;
  margin-right: 80px;
}
</style>
<style>
</style>
